﻿
namespace MockingBird.Simulator.Management
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.ServiceModel.Description;
    using System.Xml;
    using System.Xml.Serialization;
    using MockingBird.Simulator.Framework.Configuration;
    using Thinktecture.Tools.Wscf.Services.ServiceDescription.Contract;
    using Thinktecture.Tools.Wscf.Services.ServiceDescription.Metadata;

    /// <summary>
    /// This class is used to generate config files
    /// </summary>
    public class ConfigGenerator
    {
        private IMetadataDiscovery discoveryAgent;
        private ServiceDefinitionImporter wsdlImporter;
        private ServiceDefinition svcDefinition;
        private HandlerConfiguration serviceConfig;

        public ConfigGenerator(IMetadataDiscovery targetDiscoveryAgent)
        {
            this.discoveryAgent = targetDiscoveryAgent;
            this.wsdlImporter = new ServiceDefinitionImporter(targetDiscoveryAgent);
            this.svcDefinition = new ServiceDefinition();
            this.serviceConfig = new HandlerConfiguration();

        }

        /// <summary>
        /// Default constructor. Uses the simple metadata discovery agent.
        /// </summary>
        public ConfigGenerator()
            : this(new MetadataDiscovery())
        {

        }

        public void GenerateDefaultConfig(string wsdlUrl, string configFileName)
        {
            // Build the service definition
            this.svcDefinition = this.wsdlImporter.Import(wsdlUrl);

            // at this point we dont have the wsdl and if it was a multipart wsdl , naming the root would be useless
            this.serviceConfig.Wsdl = "Unknown";
            this.serviceConfig.ControlSettings = new HandlerConfigurationControlSettings();
            this.serviceConfig.ControlSettings.OperationNameInferenceStrategy = HandlerConfigurationControlSettingsOperationNameInferenceStrategy.SoapAction;

            this.serviceConfig.Operations = new List<OperationType>();
            foreach (OperationDescription op in this.svcDefinition.Operations)
            {
                this.BuildOperationElement(op);
            }
            // finally, write the configuration
            this.WriteConfiguration(configFileName);
        }

        private void BuildOperationElement(OperationDescription operation)
        {
            if (operation.IsOneWay)
            {
                this.BuildOneWayOperation(operation);
            }
            else
            {
                //this.BuildTwoWayOperation(operation);
                this.BuildXpathOperation(operation);
            }

        }

        private void BuildOneWayOperation(OperationDescription operation)
        {
            OperationType configOperation = new OperationType();
            configOperation.Name = operation.Name;
            configOperation.ResponseStrategy = ResponseStrategyType.None;
            this.serviceConfig.Operations.Add(configOperation);
        }

        private void BuildTwoWayOperation(OperationDescription operation)
        {
            OperationType configOperation = new OperationType();
            configOperation.Name = operation.Name;
            configOperation.ResponseStrategy = ResponseStrategyType.Default;
            ResponseType defaultResponse = new ResponseType();
            defaultResponse.ResponseBehaviour = ResponseBehaviourType.Standard;
            defaultResponse.FileName = operation.Name + "Response.xml";
            defaultResponse.ErrorType = ErrorType.None;
            configOperation.Item = (ResponseType)defaultResponse;
            this.serviceConfig.Operations.Add(configOperation);

        }

        private void BuildXpathOperation(OperationDescription operation)
        {
            OperationType configOperation = new OperationType();
            configOperation.Name = operation.Name;
            configOperation.ResponseStrategy = ResponseStrategyType.XPath;
            XPathBasedResponsesType xpCollection = new XPathBasedResponsesType();
            List<XPathBasedResponseType> xpList = new List<XPathBasedResponseType>();
            XPathBasedResponseType xpResponse = new XPathBasedResponseType();
            xpResponse.Expression = "Dummy";
            xpResponse.Result = "Benjy";
            xpResponse.Response = new ResponseType();
            xpResponse.Response.ResponseBehaviour = ResponseBehaviourType.Standard;
            xpResponse.Response.FileName = "Benjy.xml";
            xpResponse.Response.ErrorType = ErrorType.None;
            xpList.Add(xpResponse);
            xpCollection.XPathBasedResponse = xpList;
            configOperation.Item = (XPathBasedResponsesType)xpCollection;
            configOperation.ItemElementName = ItemChoiceType.XPathBasedResponses;

            this.serviceConfig.Operations.Add(configOperation);

        }

        private void WriteConfiguration(string fileName)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(HandlerConfiguration));
                using (XmlTextWriter xtw = new XmlTextWriter(fileName, System.Text.Encoding.UTF8))
                {
                    serializer.Serialize(xtw, this.serviceConfig);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }


        }

    }
}
